package com.supreme.studyserver.service;

import com.supreme.studyserver.component.MetalSinger;
import com.supreme.studyserver.interfacepkg.Singer;
import com.supreme.studyserver.proxy.SupremeProxy;
import com.supreme.studyserver.service.noinject.PrintService;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Service
public class ProxyService {

    @Autowired
    @Qualifier("metalSinger")
    private Singer metalSinger;

    /**
     * InvocationHandler方式封装调用
     */
    public void classInvocationHandler() {
        final String manName = metalSinger.sing("spider");
        System.out.println(manName);

        Singer proxy = (Singer) new SupremeProxy(metalSinger).getProxyInstance();
        proxy.sing("supremo");
    }

    /**
     * InvocationHandler方式直接调用
     */
    public void methodInvocationHandler() {
        final Class<? extends Singer> singerClass = metalSinger.getClass();
        Singer singer = (Singer) Proxy.newProxyInstance(singerClass.getClassLoader(), singerClass.getInterfaces(), (proxy, method, args) -> {
            System.out.println("proxyStart");
            Object invoke = method.invoke(metalSinger, args);
            System.out.println("proxyFinish");
            return invoke;
        });
        singer.sing("superMan");
        singer.singSang("superSuperMan");
    }

    /**
     * CGlib方式直接调用
     */
    public void methodMethodInterceptor() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(metalSinger.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("proxyStart");
                Object invoke = method.invoke(metalSinger, objects);
                System.out.println("proxyFinish");
                return invoke;
            }
        });
        MetalSinger metalSinger = (MetalSinger) enhancer.create();
        metalSinger.sing("ironMan");
        metalSinger.singSang("ironSuperMan");
    }

    /**
     * ProxyFactory方式
     */
    public void demoProxyFactory() {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(metalSinger);

        proxyFactory.addAdvice(new org.aopalliance.intercept.MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("proxyFactoryBefore ==>");
                final Object proceed = methodInvocation.proceed();
                System.out.println("proxyFactoryAfter ==>");
                return proceed;
            }
        });

        MetalSinger metalSinger = (MetalSinger) proxyFactory.getProxy();
        metalSinger.sing("Love World");
    }

    @Resource
    private ApplicationContext applicationContext;

    /**
     *
     */
    public void demoProxyFactoryBean() {
        PrintService printService = (PrintService) applicationContext.getBean("printServiceProxy");
        printService.printSimple();
        printService.printComplex();
    }

    public void demoAutoProxyCreator() {
        AuthService authService = (AuthService) applicationContext.getBean("authService");
        authService.showUser();
        authService.showAdmin();
    }
}
